﻿using Microsoft.AspNetCore.Http;

namespace AntBlazor.Extensions;

/// <summary>
/// 请求上下文扩展类。
/// </summary>
public static class RequestExtension
{
    /// <summary>
    /// 判断是否是POST请求。
    /// </summary>
    /// <param name="request">Http请求对象。</param>
    /// <returns></returns>
    public static bool IsPost(this HttpRequest request) => request.Method == "POST" && request.Form != null;

    /// <summary>
    /// 判断是否是指定名称的表单处理者。
    /// </summary>
    /// <param name="request">Http请求对象。</param>
    /// <param name="name">表单名称。</param>
    /// <returns></returns>
    public static bool IsHandler(this HttpRequest request, string name)
    {
        if (!request.IsPost())
            return false;

        if (!request.Form.ContainsKey("_handler"))
            return false;

        var handler = request.Form["_handler"];
        return handler == name;
    }

    /// <summary>
    /// 获取指定参数的请求值。
    /// </summary>
    /// <typeparam name="T">参数类型。</typeparam>
    /// <param name="request">Http请求对象。</param>
    /// <param name="name">参数名称。</param>
    /// <returns></returns>
    public static T Get<T>(this HttpRequest request, string name)
    {
        var value = string.Empty;
        if (request.Query.ContainsKey(name))
            value = request.Query[name];
        else if (request.IsPost() && request.Form.ContainsKey(name))
            value = request.Form[name];

        return (T)ConvertTo(typeof(T), value);
    }

    /// <summary>
    /// 获取POST表单请求数据对象。
    /// </summary>
    /// <typeparam name="T">对象类型。</typeparam>
    /// <param name="request">Http请求对象。</param>
    /// <returns></returns>
    public static T GetModel<T>(this HttpRequest request)
    {
        if (!request.IsPost())
            return default;

        var model = Activator.CreateInstance<T>();
        foreach (var item in request.Form)
        {
            if (item.Key.StartsWith('_'))
                continue;

            var property = typeof(T).GetProperty(item.Key);
            if (property != null)
            {
                var value1 = ConvertTo(property.PropertyType, item.Value);
                property.SetValue(model, value1, null);
            }
        }
        return model;
    }

    private static object ConvertTo(Type type, object value, object defaultValue = null)
    {
        if (value == null || value == DBNull.Value)
            return defaultValue;

        var valueString = value.ToString();
        if (type == typeof(string))
            return Convert.ChangeType(valueString, type);

        valueString = valueString.Trim();
        if (valueString.Length == 0)
            return defaultValue;

        if (type.IsEnum)
            return Enum.Parse(type, valueString, true);

        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
            type = Nullable.GetUnderlyingType(type);

        if (type == typeof(bool) || type == typeof(bool?))
            valueString = ",是,1,Y,YES,TRUE,".Contains(valueString.ToUpper()) ? "True" : "False";

        try
        {
            return Convert.ChangeType(valueString, type);
        }
        catch
        {
            return defaultValue;
        }
    }
}